import os
from datetime import datetime, timedelta
import random
import json
from typing import Dict, Any, Optional
from langchain.tools import tool
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI
from mytools import vector_store_tools
from langchain.tools.retriever import create_retriever_tool

current_dir = os.path.dirname(os.path.abspath(__file__))
# 回退到项目根目录（mypro/），然后定位文件
path = os.path.join(current_dir, "../../mypro/my_file/my_text.txt")
path = os.path.normpath(path)

from typing import List
from sklearn.metrics import precision_score, recall_score
import numpy as np


class ContractEvaluator:
    """合同生成质量评估工具"""
    @staticmethod
    def evaluate(expected: Dict, actual: Dict) -> Dict:
        """
        评估合同生成质量
        参数:
            expected: 期望包含的关键字段
            actual: 实际生成的合同
        返回:
            {
                "score": float,  # 总分(0-1)
                "missing_fields": List[str],  # 缺失字段
                "feedback": str  # 评估反馈
            }
        """
        missing = []
        for field in expected:
            if field not in actual:
                missing.append(field)

        score = 1 - len(missing) / len(expected) if expected else 1.0

        return {
            "score": score,
            "missing_fields": missing,
            "feedback": f"缺失{len(missing)}个关键字段" if missing else "所有关键字段完整"
        }


class AuditEvaluator:
    """审核性能评估工具"""

    @staticmethod
    def evaluate(actual: List[Dict], predicted: List[Dict]) -> Dict:
        """
        评估审核准确性
        参数:
            actual: 实际正确结果
            predicted: 模型预测结果
        返回:
            {
                "accuracy": float,  # 准确率
                "error_cases": List[Dict]  # 错误案例
            }
        """
        correct = 0
        errors = []

        for a, p in zip(actual, predicted):
            if a.get('is_approved') == p.get('is_approved'):
                correct += 1
            else:
                errors.append({
                    "expected": a.get('is_approved'),
                    "actual": p.get('is_approved'),
                    "input": a.get('input_data', {})
                })

        return {
            "accuracy": correct / len(actual) if actual else 0,
            "error_cases": errors
        }
# 评估工具
@tool
def evaluate_retrieval(query: str) -> Dict:
    """评估条款检索质量"""
    return vector_store_tools.VectorStoreTools(path).evaluate_retrieval(query)
@tool
def evaluate_contract(expected: Dict, actual: Dict) -> Dict:
    """评估生成的合同质量"""
    return ContractEvaluator.evaluate(expected, actual)


@tool
def evaluate_audit(actual: List[Dict], predicted: List[Dict]) -> Dict:
    """评估审核性能"""
    return AuditEvaluator.evaluate(actual, predicted)

retriever=vector_store_tools.VectorStoreTools(path).get_retriever('hetong')
retriever_tool=create_retriever_tool(
    retriever=retriever,  # 关键修正：使用retriever参数而不是vectorstore
    name="insurance_clause_retriever",  # 更符合业务场景的名称
    description="从保险条款库中检索相关条款内容，用于合同生成和审核参考"
)



# 初始化LLM - 使用阿里云通义千问
llm = ChatOpenAI(
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    model="qwen-max",
    temperature=0.1  # 低随机性保证审核严谨性
)
from goods import models
from login import models
from orders import models
#根据用户输入的信息生成一份保险合同


# 在工具列表中添加
@tool
def store_insurance_contract(contract_data: Dict) -> Dict:
    """将保险合同存入数据库"""
    return vector_store_tools.VectorStoreTools(path).add_contract_to_vectorstore(contract_data)

@tool
def search_insurance_contracts(query: str) -> List[Dict]:
    """检索历史保险合同"""
    return vector_store_tools.VectorStoreTools(path).search_contracts(query)


@tool
def create_insurance_contract(
        aname,bname,acard_id,bcard_id,
        phone,relationship,order_id,effective_date=None,term_years=1
        ):
    """
    保险合同生成工具，根据用户提供的投保信息生成标准保险合同
    参数:
        aname: 投保人姓名
        bname: 被保人姓名
        acard_id: 投保人身份证号(18位)
        bcard_id: 被保人身份证号(18位)
        phone: 投保人联系方式
        relationship: 投保人与被保人关系(默认:"本人")
        order_id:订单id
        effective_date: 保单生效日期(YYYY-MM-DD，默认当前日期+7天)
        term_years: 保险期限(年)(默认:1)

    返回:
        dict: 包含合同内容和状态的字典
        {
            "success": bool,            # 是否成功生成合同
            "contract_id": str,         # 合同编号
            "contract_content": dict,   # 合同内容详情
            "user_info": dict,          # 用户验证信息
            "product_info": dict,       # 产品信息
            "error_message": str,      # 错误信息(如果有)
            "generated_at": str         # 合同生成时间
        }
    """
    # 初始化返回结果
    result = {
        "success": False,
        "contract_id": "",
        "contract_content": {},
        "user_info": {},
        "product_info": {},
        "error_message": "",
        "generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }

    try:
        # 1. 验证用户信息
        user_data = models.UserModel.objects.filter(phone=phone).first()
        if not user_data:
            result["error_message"] = "用户不存在"
            return result

        use_id = user_data.id
        check_phone = user_data.phone
        is_card = user_data.auth.id_number

        # 2. 验证手机号和身份证号
        if phone != check_phone:
            result["error_message"] = "手机号不匹配"
            return result

        if is_card != acard_id:
            result["error_message"] = "投保人身份证号不匹配"
            return result

        # 3. 获取产品信息
        order = models.Order.objects.filter(order_user=use_id, order_status='未审核',order_id=order_id).first()
        if not order:
            result["error_message"] = "未找到待审核的订单"
            return result

        product = order.order_product
        product_type = product.category
        coverage_amount = product.coverage_amount

        # 4. 验证必填字段
        if not all([aname, bname, acard_id, bcard_id, phone, relationship]):
            result["error_message"] = "请输入完整信息"
            return result

        # 5. 验证身份证号格式
        if len(acard_id) != 18 or len(bcard_id) != 18:
            result["error_message"] = "身份证号必须为18位"
            return result

        # 6. 验证关系类型
        valid_relationships = ["本人", "配偶", "子女", "父母"]
        if relationship not in valid_relationships:
            result["error_message"] = f"关系类型无效，应为{valid_relationships}之一"
            return result
        # 查询合同的类型
        contract_type = order.order_product.category.name

        user_data = models.UserModel.objects.filter(phone=phone).first()
        if not user_data or not user_data.auth:
            result["error_message"] = "用户未完成实名认证"
            return result

        # 7. 设置默认生效日期(7天后)
        if not effective_date:
            effective_date = (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d")

        # 8. 验证生效日期
        try:
            eff_date = datetime.strptime(effective_date, "%Y-%m-%d")
            today = datetime.now()

            if eff_date.date() < today.date():
                result["error_message"] = "生效日期不能早于当前日期"
                return result

            if (eff_date.date() - today.date()).days > 30:
                result["error_message"] = "生效日期不能超过30天后"
                return result
        except ValueError:
            result["error_message"] = "日期格式无效(应为YYYY-MM-DD)"
            return result

        # 9. 生成合同编号(示例: IC-年月日-随机4位)
        contract_id = f"IC-{datetime.now().strftime('%Y%m%d')}-{str(random.randint(1000, 9999))}"

        # 10. 构建合同内容
        contract_content = {
            "contract_info": {
                "order_id":order_id,
                "contract_id": contract_id,
                "generated_at": result["generated_at"],
                "effective_date": effective_date,
                "expiry_date": (eff_date + timedelta(days=term_years * 365)).strftime("%Y-%m-%d"),
                "product_type": product_type.name if hasattr(product_type, 'name') else str(product_type),  # 改为获取名称
                "coverage_amount": float(coverage_amount) if coverage_amount else 0.0,  # 确保是基本类型
                "term_years": int(term_years),
                "status": "已审核，待支付"
            },
            "applicant_info": {
                "name": aname,
                "id_number": acard_id,
                "phone": phone,
                "user_id": use_id
            },
            "insured_info": {
                "name": bname,
                "id_number": bcard_id,
                "relationship": relationship
            },
            "clauses": [
                f"本保险合同依据《中华人民共和国保险法》及相关法律法规订立,",
                f"投保人{aname}自愿为被保人{bname}投保本保险",
                f"保险金额为人民币{coverage_amount}元整",
                f"合约类型为{contract_type},订单号为{order_id}"
                f"保险期限为{term_years}年，自{effective_date}起至{(eff_date + timedelta(days=term_years * 365)).strftime('%Y-%m-%d')}止",
                "具体保险责任和责任免除详见保险条款"
            ],
            "signature_required": {
                "applicant": False,
                "insured": relationship != "本人"
            }
        }
        # 11. 保存用户和产品信息到结果
        result.update({
            "user_info": {
                "user_id": use_id,
                "phone": phone,
                "id_number": acard_id
            },
            "product_info": {
                "product_id": product.id,
                "product_type": product_type,
                "coverage_amount": coverage_amount,
                "order_id": order.id
            }
        })
        # 12. 返回成功结果
        result.update({
            "success": True,
            "contract_id": contract_id,
            "contract_content": contract_content
        })
    except Exception as e:
        result["error_message"] = f"合同生成失败: {str(e)}"
        import traceback
        traceback.print_exc()
    if result["success"]:
        # 存储合同到向量数据库
        storage_result = vector_store_tools.VectorStoreTools(path).add_contract_to_vectorstore(
            result["contract_content"]
        )
        result["storage_status"] = storage_result

    return result
# 保险资料审核工具
@tool
def insurance_application_audit(application_data,strict_mode):
    """
    保险投保资料审核工具，验证投保申请的完整性和合规性

    参数:
        application_data: 投保资料字典，必须包含:
            - policy_effective_date: 保单生效时间(YYYY-MM-DD)
            - applicant: 投保人信息(dict)
                - name: 姓名
                - id_number: 证件号
                - contact: 联系方式
            - insured: 被保人信息(dict)
                - name: 姓名
                - id_number: 证件号
                - relationship: 与投保人关系
        strict_mode: 是否启用严格模式(默认True)

    返回:
        dict: 审核结果
        {
            "is_approved": bool,           # 是否通过审核
            "rejection_reasons": list,     # 拒绝原因列表
            "missing_fields": list,        # 缺失字段列表
            "validation_details": dict,    # 各字段验证详情
            "suggestions": list            # 改进建议
        }
    """
    results = {
        "is_approved": True,
        "rejection_reasons": [],
        "missing_fields": [],
        "validation_details": {},
        "suggestions": []
    }
    # 1. 检查必需字段是否存在
    required_fields = [
        "policy_effective_date",
        "applicant",
        "insured"
    ]
    applicant_required = ["name", "id_number", "contact"]
    insured_required = ["name", "id_number", "relationship"]

    # 检查顶级必需字段
    for field in required_fields:
        if field not in application_data:
            results["missing_fields"].append(field)
            results["is_approved"] = False

    # 检查投保人信息
    if "applicant" in application_data:
        for field in applicant_required:
            if field not in application_data["applicant"]:
                results["missing_fields"].append(f"applicant.{field}")
            else:
                # 验证身份证号格式(简单示例)
                if field == "id_number" and len(application_data["applicant"][field]) != 18:
                    results["validation_details"][f"applicant.{field}"] = "证件号长度不符"

    # 检查被保人信息
    if "insured" in application_data:
        for field in insured_required:
            if field not in application_data["insured"]:
                results["missing_fields"].append(f"insured.{field}")
            elif field == "relationship":
                valid_relationships = ["本人", "配偶", "子女", "父母"]
                if application_data["insured"][field] not in valid_relationships:
                    results["validation_details"][f"insured.{field}"] = f"关系类型无效，应为{valid_relationships}"

    # 2. 验证生效时间
    if "policy_effective_date" in application_data:
        try:
            effective_date = datetime.strptime(application_data["policy_effective_date"], "%Y-%m-%d")
            today = datetime.now()

            # 生效日期不能早于当前日期
            if effective_date.date() < today.date():
                results["validation_details"]["policy_effective_date"] = "生效日期不能早于当前日期"
                results["is_approved"] = False

            # 严格模式下：生效日期不能超过30天后
            if strict_mode and (effective_date.date() - today.date()).days > 30:
                results["validation_details"]["policy_effective_date"] = "生效日期不能超过30天后"
                results["suggestions"].append("请确认生效日期是否合理")

        except ValueError:
            results["validation_details"]["policy_effective_date"] = "日期格式无效(应为YYYY-MM-DD)"
            results["is_approved"] = False

    # 3. 综合判断
    if results["missing_fields"]:
        results["rejection_reasons"].append(f"缺少必要字段: {', '.join(results['missing_fields'])}")

    if results["validation_details"]:
        reasons = [f"{k}: {v}" for k, v in results["validation_details"].items()]
        results["rejection_reasons"].extend(reasons)

    return results


@tool
def update_order_status(phone: str,order_id) -> Dict[str, Any]:
    """
    更新订单状态工具，当保险申请审核通过后，将订单状态从'未审核'改为'已审核,未支付'

    参数:
        phone: 投保人手机号(用于标识用户)
        order_id:订单id (用于标识订单)

    返回:
        dict: 包含操作结果的字典
        {
            "success": bool,       # 操作是否成功
            "message": str,        # 结果消息
            "user_id": int,       # 用户ID(如果找到)
            "updated_count": int,  # 更新的订单数量
            "error": str          # 错误信息(如果有)
        }
    """
    from django.db import transaction
    from orders.models import Order  # 明确指定使用orders应用的Order模型

    result = {
        "success": False,
        "message": "",
        "user_id": None,
        "updated_count": 0,
        "error": ""
    }
    try:
        with transaction.atomic():
            # 1. 验证并获取用户信息
            if not phone or len(phone) != 11:
                result["message"] = "无效的手机号格式"
                result["error"] = "手机号必须为11位数字"
                return result

            user_data = models.UserModel.objects.filter(phone=phone).first()
            if not user_data:
                result["message"] = "用户不存在"
                return result

            user_id = user_data.id
            result["user_id"] = user_id

            # 2. 查找待审核订单 - 添加更详细的日志
            pending_orders = Order.objects.filter(
                order_user=user_id,
                order_status='未审核',  # 确保与数据库中实际存储的状态值完全一致
                order_id=order_id
            )
            print(f"找到 {pending_orders.count()} 条待审核订单")  # 调试日志

            if not pending_orders.exists():
                result["message"] = "没有找到待审核的订单"
                return result

            # 3. 执行订单状态更新
            updated_count = pending_orders.update(
                order_status='已审核,未支付',  # 确保状态值与业务要求一致
            )

            print(f"成功更新 {updated_count} 条订单状态")  # 调试日志

            result["updated_count"] = updated_count
            result["success"] = True
            result["message"] = f"成功更新{updated_count}条订单状态为'已审核,未支付'"

            return result

    except Exception as e:
        result["error"] = str(e)
        result["message"] = "订单状态更新失败"
        # 记录完整错误堆栈
        import traceback
        traceback.print_exc()
        return result

# 系统提示模板 - 保险专业版
SYSTEM_PROMPT = """您是一名专业的保险核保助手，负责审核投保申请资料。
工作流程：
1. 先使用insurance_application_audit审核投保资料
2. 审核通过后使用create_insurance_contract生成合同
3. 若审核不通过，需明确告知用户原因
4. 若用户补充信息后再次提交，需重新审核
5. 请你展示你检索rag向量数据库的流程，目前任在开发阶段
6. 若审核通过使用Updata_OrderModel,更新订单表中的状态，审核错误或者系统错误则不能修改状态
end. 如果订单状态发生改变，审核通过

新增规则：
7. 生成合同时必须按以下步骤操作：
   a. 先使用insurance_clause_retriever检索相关保险条款
   b. 将检索到的条款与用户需求结合
   c. 确保生成的合同条款与检索结果一致
   d. 在最终合同中注明参考的条款来源
   e. 检索insurance_clause_retriever时，确保返回的条款与用户需求相关，丰富合同内容
   f. 使用store_insurance_contract工具将生成的合同存入数据库
   g. 确认存储成功后告知用户合同编号和存储状态
8. 评估要求：
    评估要求：
    1. 每次检索后评估检索质量
    2. 合同生成后评估合同完整性
    3. 定期评估审核准确性
    4. 根据评估结果优化流程
    5. 详细说明模型的评估结果


请确保：
1. 必需字段完整：
   - 保单生效时间(policy_effective_date)
   - 投保人信息(applicant): 姓名、证件号、联系方式
   - 被保人信息(insured): 姓名、证件号、与投保人关系
   - 不得具有敏感词
   - 不得包含虚假信息
   - 不得包含不实言论
   - 不得包含违规信息
   - 不得包含不道德行为
   - 不得包含不合法,不道德,不合规行为
   

2. 验证规则：
   - 生效日期必须为未来日期且不超过30天,否则拒绝，拒绝后告诉用户可以填写的时间范围
   - 投保人和被保人证件号必须为18位,必须通过实名认证
   - 被保人关系必须是[本人, 配偶, 子女, 父母]之一

3. 审核结果需包含：
   - 是否通过
   - 拒绝原因(如未通过)
   - 改进建议
   - 展示完整的合同内容(如通过)
   - 合同编号(如通过) 
请严格遵循保险监管要求，对可疑申请保持警惕。
"""
# 创建对话提示模板
prompt = ChatPromptTemplate.from_messages([
    SystemMessage(content=SYSTEM_PROMPT),
    MessagesPlaceholder(variable_name="chat_history", optional=True),
    HumanMessagePromptTemplate.from_template("{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad")
])
# 准备工具列表
tools = [
         insurance_application_audit,
         create_insurance_contract,
         update_order_status,
         retriever_tool,
         evaluate_retrieval,
         evaluate_contract,
         evaluate_audit,
        store_insurance_contract,  # 新增
        search_insurance_contracts  # 新增
]
# 创建函数型Agent
agent = create_openai_functions_agent(
    llm=llm,
    prompt=prompt,
    tools=tools
)
# 创建Agent执行器
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,
    handle_parsing_errors=True
)

if __name__ == "__main__":
    # 模拟完整流程
    application_data = {
        "policy_effective_date": (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d"),
        "applicant": {
            "name": "张三",
            "id_number": "411702200508260837",
            "contact": "19139230505"
        },
        "insured": {
            "name": "张三",
            "id_number": "110105199003078888",
            "relationship": "本人"
        }
    }


    # 1. 先审核
    agent_response = agent_executor.invoke({
        "input": f"请审核这份投保申请: {application_data}",
        "chat_history": []
    })
    print("审核结果:", agent_response["output"])

    # 2. 如果审核通过，生成合同
    if "审核通过" in agent_response["output"]:
        contract_data = {
            "aname": application_data["applicant"]["name"],
            "bname": application_data["insured"]["name"],
            "acard_id": application_data["applicant"]["id_number"],
            "bcard_id": application_data["insured"]["id_number"],
            "phone": application_data["applicant"]["contact"],
            "relationship": application_data["insured"]["relationship"],
            "effective_date": application_data["policy_effective_date"]
        }
        contract_result = create_insurance_contract(**contract_data)
        print("\n生成的合同:", json.dumps(contract_result, indent=2, ensure_ascii=False))


